package com.anita.member.util;


import com.anita.member.config.JwtConfig;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 *
 * @author wuyunbin
 * @since 2025-07-22
 */
@Component
public class JwtUtil {
    @Resource
    private JwtConfig jwtConfig;

    /**
     * 用户类型枚举
     */
    public enum UserType {
        ADMIN,
        SELLER,
        MEMBER
    }



    /**
     * 获取访问令牌的密钥
     * @return 密钥
     */
    private Key getAccessTokenKey() {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hashedKey = md.digest(jwtConfig.getAccessTokenKey().getBytes(StandardCharsets.UTF_8));
            return Keys.hmacShaKeyFor(hashedKey);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to hash JWT access token key", e);
        }
    }

    /**
     * 获取刷新令牌的密钥
     * @return 密钥
     */
    private Key getRefreshTokenKey() {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hashedKey = md.digest(jwtConfig.getRefreshTokenKey().getBytes(StandardCharsets.UTF_8));
            return Keys.hmacShaKeyFor(hashedKey);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to hash JWT refresh token key", e);
        }
    }

    /**
     * 生成访问令牌
     *
     * @param userType 用户类型
     * @param userId 用户ID
     * @return 访问令牌
     */
    public String generateAccessToken(UserType userType, Long userId) {
        return generateToken(userType, userId, jwtConfig.getAccessTokenTtl(), getAccessTokenKey());
    }

    /**
     * 生成刷新令牌
     *
     * @param userType 用户类型
     * @param userId 用户ID
     * @return 刷新令牌
     */
    public String generateRefreshToken(UserType userType, Long userId) {
        return generateToken(userType, userId, jwtConfig.getRefreshTokenTtl(), getRefreshTokenKey());
    }

    /**
     * 生成令牌
     *
     * @param userType 用户类型
     * @param userId 用户ID
     * @param expiration 过期时间
     * @param key 密钥
     * @return 令牌
     */
    private String generateToken(UserType userType, Long userId, long expiration, Key key) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("userType", userType.name());

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        Date exp = new Date(nowMillis + expiration);

        return "Bearer " + Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(exp)
                .signWith(key)
                .compact();
    }

    /**
     * 解析访问令牌
     *
     * @param token 令牌
     * @return 声明
     */
    public Claims parseAccessToken(String token) {
        return parseToken(token, getAccessTokenKey());
    }

    /**
     * 解析刷新令牌
     *
     * @param token 令牌
     * @return 声明
     */
    public Claims parseRefreshToken(String token) {
        return parseToken(token, getRefreshTokenKey());
    }

    /**
     * 解析令牌
     *
     * @param token 令牌
     * @param key 密钥
     * @return 声明
     */
    private Claims parseToken(String token, Key key) {
        // 移除可能的"Bearer "前缀
        if (token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 判断令牌是否过期
     *
     * @param claims 声明
     * @return 是否过期
     */
    public boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }

    /**
     * 从声明中获取用户ID
     *
     * @param claims 声明
     * @return 用户ID
     */
    public Long getUserIdFromClaims(Claims claims) {
        return claims.get("userId", Long.class);
    }

    /**
     * 从声明中获取用户类型
     *
     * @param claims 声明
     * @return 用户类型
     */
    public UserType getUserTypeFromClaims(Claims claims) {
        String userTypeStr = claims.get("userType", String.class);
        return UserType.valueOf(userTypeStr);
    }

    /**
     * 验证令牌的用户类型是否匹配
     *
     * @param claims 声明
     * @param expectedType 期望的用户类型
     * @return 是否匹配
     */
    public boolean validateUserType(Claims claims, UserType expectedType) {
        try {
            UserType tokenUserType = getUserTypeFromClaims(claims);
            return expectedType == tokenUserType;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 验证访问令牌是否有效
     *
     * @param token 访问令牌
     * @return 是否有效
     */
    public boolean validateAccessToken(String token) {
        try {
            // 解析访问令牌
            Claims claims = parseAccessToken(token);
            
            // 检查令牌是否过期
            if (isTokenExpired(claims)) {
                return false;
            }
            
            // 令牌有效
            return true;
        } catch (Exception e) {
            // 解析失败（无效的令牌格式、签名不正确等）
            return false;
        }
    }
    
    /**
     * 验证刷新令牌是否有效
     *
     * @param token 刷新令牌
     * @return 是否有效
     */
    public boolean validateRefreshToken(String token) {
        try {
            // 解析刷新令牌
            Claims claims = parseRefreshToken(token);
            
            // 检查令牌是否过期
            if (isTokenExpired(claims)) {
                return false;
            }
            
            // 令牌有效
            return true;
        } catch (Exception e) {
            // 解析失败（无效的令牌格式、签名不正确等）
            return false;
        }
    }
    

}